/*
 * Copyright 2025 LinQingYing. and contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of this source code is governed by the Apache License 2.0,
 * which allows users to freely use, modify, and distribute the code,
 * provided they adhere to the terms of the license.
 *
 * The software is provided "as-is", and the authors are not responsible for
 * any damages or issues arising from its use.
 *
 */

package org.cangnova.cangjie.project.service

import com.intellij.openapi.Disposable
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.messages.Topic
import org.cangnova.cangjie.project.model.CjModule
import org.cangnova.cangjie.project.model.CjProject
import org.cangnova.cangjie.result.CjProcessResult


val Project.cangjieProjectService: CjProjectsService get() = CjProjectsService.getInstance(this)

/**
 * 仓颉项目管理服务接口
 *
 * 提供项目的发现、创建、缓存和管理功能
 */
@Service(Service.Level.PROJECT)
interface CjProjectsService {
val intellijProject: Project
    companion object {
        /**
         * 获取服务实例
         */
        fun getInstance(project: Project): CjProjectsService {
            return project.getService(CjProjectsService::class.java)
        }

        val CANGJIE_PROJECTS_TOPIC: Topic<CangJieProjectsListener> = Topic(
            "CangJie projects changes",
            CangJieProjectsListener::class.java
        )
        val CANGJIE_PROJECTS_REFRESH_TOPIC: Topic<CangJieProjectsRefreshListener> = Topic(
            "CangJie refresh",
            CangJieProjectsRefreshListener::class.java
        )

    }

    enum class RefreshStatus {
        SUCCESS,
        FAILURE,
        CANCEL
    }

    interface CangJieProjectsRefreshListener {
        fun onRefreshStarted()
        fun onRefreshFinished(status: RefreshStatus)
    }

    fun interface CangJieProjectsListener {
        fun cangjieProjectsUpdated(service: CjProjectsService, projects: Collection<CjProject>)
    }

    /**
     * 获取所有仓颉项目
     * 一般情况下，只有一个CjProject，但是当出现在同一个窗口打开多个项目时，才会有多个
     */
    val allProjects: List<CjProject>

    /**
     * 根据根目录查找项目
     *
     * @param rootDir 项目根目录
     * @return 找到的项目，如果不存在返回 null
     */
    fun findProject(rootDir: VirtualFile): CjProject?

    /**
     * 根据名称查找项目
     *
     * @param name 项目名称
     * @return 找到的项目，如果不存在返回 null
     */
    fun findProjectByName(name: String): CjProject?

    /**
     * 发现并创建项目
     *
     * 通过扩展点机制尝试识别并创建项目
     *
     * @param rootDir 项目根目录
     * @return 创建的项目，如果无法识别返回 null
     */
    fun discoverProject(rootDir: VirtualFile): CjProject?

    /**
     * 添加项目到缓存
     *
     * @param project 要添加的项目
     */
    fun addProject(project: CjProject)

    /**
     * 从缓存中移除项目
     *
     * @param project 要移除的项目
     */
    fun removeProject(project: CjProject)

    /**
     * 刷新所有项目（完整刷新，包括索引重建和根目录更新）
     *
     * 注意：此方法会触发完整的项目更新流程，包括：
     * - 重新加载所有项目配置
     * - 重置索引
     * - 更新项目根目录（触发全量扫描）
     * - 发布项目更新事件
     *
     * 仅在项目列表结构发生变化时使用。
     */
    fun refreshAllProjects()

    /**
     * 刷新指定项目
     *
     * @param project 要刷新的项目
     */
    fun refreshProject(project: CjProject)

    /**
     * 根据文件查找所属项目
     *
     * @param file 要查找的文件
     * @return 文件所属的项目，如果不属于任何项目返回 null
     */
    fun findProjectForFile(file: VirtualFile): CjProject?

    /**
     * 根据文件查找所属模块
     *
     * @param file 要查找的文件
     * @return 文件所属的模块，如果不属于任何模块返回 null
     */
    fun findModuleForFile(file: VirtualFile): CjModule?

    val initialized: Boolean


    /**
     * 创建项目
     */
    fun createProject(
        sdkId: String,
        owner: Disposable,
        directory: VirtualFile,
        projectType: String = "executable",
    ): CjProcessResult<GeneratedFilesHolder>


}


data class GeneratedFilesHolder(val manifest: VirtualFile, val sourceFiles: List<VirtualFile>)
